var shapes = [];
var isMoveable = false;
var factory = createPen;
var theFill = "noFill";
var theBorder = "black";
var isText = false;
var theSize = "10pt";
var theLineSize = 1;
var isEq = false;
var lastShape;
var nextShape;

function Shape(x, y, endX, endY) {
    this.x = (x === undefined) ? 0 : x;
    this.y = (y === undefined) ? 0 : y;
    this.endX = (endX === undefined) ? 0 : endX;
    this.endY = (endX === undefined) ? 0 : endY;
}
function setBorder() {
    var newBorder = document.getElementById("newBorder");
    theBorder = newBorder.options[newBorder.selectedIndex].value;
}
function setFill() {
    var newFill = document.getElementById("newFill");
    theFill = newFill.options[newFill.selectedIndex].value;
}
function setSize() {
    var newSize = document.getElementById("newSize");
    theSize = newSize.options[newSize.selectedIndex].value;
}
function setLineSize() {
    var newLineSize = document.getElementById("newLineSize");
    theLineSize = newLineSize.options[newLineSize.selectedIndex].value;
}

function setEquation() {
    isEq = true;
}

function Img(x, y, eq) {
    this.ClassName = "Img";
    this.x = x;
    this.y = y;
    this.eq = eq;
}

function Rectangle(x, y, border, fill, linesize) {
    this.ClassName = "Rectangle";
    this.x = x
    this.y = y;
    this.endX = x;
    this.endY = y;
    this.border = border;
    this.fill = fill;
    this.lineSize = linesize;
}

function Circle(x, y, border, fill, linesize) {
    this.ClassName = "Circle";
    this.x = x;
    this.y = y;
    this.endX = x;
    this.endY = y;
    this.border = border;
    this.fill = fill;
    this.lineSize = linesize;
}

function Pen(x, y, border, fill, linesize) {
    this.ClassName = "Pen";
    this.points = [];
    this.points.push({"x" : x, "y" : y ,"border" : border, "linesize" : linesize});

}

function Line(x, y, border, fill, linesize) {
    this.ClassName = "Line";
    this.x = x
    this.y = y;
    this.endX = x;
    this.endY = y;
    this.border = border;
    this.lineSize = linesize;

}
function Text(x, y, text, border, fill, font, size) {
    this.ClassName = "Text";
    this.x = x;
    this.y = y;
    this.fill = fill;
    this.border = border;
    this.text = text;
    this.font = font;
    this.size = size;
}
function Moveable() {
    isMoveable = true;
    isText = false;
}
function setRect() {
    isMoveable = false;
    isText = false;
    factory = createRectangle;
}
function setCircle() {
    isMoveable = false;
    isText = false;
    factory = createCircle;
}
function setLine() {
    isMoveable = false;
    isText = false;
    factory = createLine;
}
function setPen() {
    isMoveable = false;
    isText = false;
    factory = createPen;
}
function createRectangle(x, y, border, fill, lineSize) {
    return new Rectangle(x, y, border, fill, lineSize);
}
function createCircle(x, y, border, fill, lineSize) {
    return new Circle(x, y, border, fill, lineSize);
}
function createLine(x, y, border, fill, lineSize) {
    return new Line(x, y, border, fill, lineSize);
}
function createPen(x, y, border, fill, lineSize) {
    return new Pen(x, y, border, fill, lineSize);
}
function setText() {
    //factory = createText;
    isText = true;
}
function createText(x, y, text, border, fill, font, size) {
    return new Text(x, y, text, border, fill, font, size);
}

function createImg(x, y, eq) {
    return new Img(x, y, eq);
}

function Redraw(ctx) {
    if (shapes.length != undefined) {
        for (var i = 0; i < shapes.length; i++) {
            shapes[i].Draw(ctx);
        }
    }
}

Rectangle.prototype.Draw = function (ctx) {
    var height = this.endY - this.y;
    var width = this.endX - this.x;
    ctx.fillStyle = this.fill;
    ctx.lineWidth = this.lineSize;
    if (this.fill != "noFill") {
        ctx.fillRect(this.x, this.y, width, height);
    }
    ctx.clearRect(0, 0, this.width, this.height);
    ctx.strokeStyle = this.border;
    ctx.strokeRect(this.x, this.y, width, height);
}

Rectangle.prototype.SetEnd = function (x, y) {
    this.endX = x;
    this.endY = y;
}

Line.prototype.Draw = function (ctx) {
    ctx.beginPath();
    ctx.moveTo(this.x, this.y);
    ctx.lineWidth = this.lineSize;
    ctx.lineTo(this.endX, this.endY);
    ctx.strokeStyle = this.border;
    ctx.stroke();
}

Line.prototype.SetEnd = function (x, y) {
    this.endX = x;
    this.endY = y;
}

Pen.prototype.SetEnd = function (x, y) {

    this.points.push({"x" : x, "y" : y, "linesize" : theLineSize });
}
Pen.prototype.Draw = function(ctx) {
    var begin = this.points[0];
    var nextLine;
    ctx.beginPath();
    ctx.lineWidth = this.points[0].linesize;
    ctx.moveTo(begin.x, begin.y);

    for (var i = 0; i < this.points.length - 1; i++) {
        nextLine = this.points[i + 1];
        ctx.lineWidth = this.points[i].linesize;
        ctx.lineTo(nextLine.x, nextLine.y);
        ctx.strokeStyle = this.points[i].border;
        ctx.stroke();

    }

}

Circle.prototype.Draw = function (ctx) {
    var radius = (this.y - this.endY) + (this.x - this.endX);
    radius = Math.abs(radius / 2);
    ctx.beginPath();
    ctx.arc(this.x, this.y, radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = this.fill;
    ctx.lineWidth = this.lineSize;
    if (this.fill != "noFill") {
        ctx.fill();
    }

    ctx.strokeStyle = this.border;
    ctx.stroke();
}

Circle.prototype.SetEnd = function (x, y) {
    this.x = x;
    this.y = y;
}

Text.prototype.Draw = function(ctx) {
    ctx.fillStyle = this.border;
    ctx.font = this.size + " " + this.font;
    ctx.fillText(this.text, this.x, this.y - 100);

}

Img.prototype.Draw = function(ctx) {
    var img = new Image();
    var x = this.x;
    var y = this.y - 100;
    img.onload = function() {
        ctx.drawImage(img, x, y);
        ctx.stroke();
    };
    img.src = this.eq;


}

Img.prototype.SetEnd = function(ctx) {
}

Text.prototype.SetEnd = function(ctx) {
}

// Draws this shape to a given context
Shape.prototype.draw = function(ctx) {
    ctx.fillStyle = this.fill;
    ctx.fillRect(this.x, this.y, this.w, this.h);
}

// Determine if a point is inside the shape's bounds
Shape.prototype.contains = function(mx, my) {
    // All we have to do is make sure the Mouse X,Y fall in the area between
    // the shape's X and (X + Height) and its Y and (Y + Height)
    return  (this.x <= mx) && (this.x + this.w >= mx) &&
        (this.y <= my) && (this.y + this.h >= my);
}
function CanvasState(canvas) {
    this.canvas = canvas;
    this.width = canvas.width;
    this.height = canvas.height;

    var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
    if (document.defaultView && document.defaultView.getComputedStyle) {
        this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10) || 0;
        this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10) || 0;
        this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10) || 0;
        this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10) || 0;
    }
    // Some pages have fixed-position bars (like the stumbleupon bar) at the top or left of the page
    // They will mess up mouse coordinates and this fixes that
    var html = document.body.parentNode;
    this.htmlTop = html.offsetTop;
    this.htmlLeft = html.offsetLeft;

    // **** Keep track of state! ****

    this.valid = false; // when set to false, the canvas will redraw everything
    this.shapes = [];  // the collection of things to be drawn
    this.dragging = false; // Keep track of when we are dragging

    this.selection = null;
    this.dragoffx = 0; // See mousedown and mousemove events for explanation
    this.dragoffy = 0;
    this.dragging = false;
    this.selectionColor = '#CC0000';
    this.selectionWidth = 2;
    this.interval = 30;
}

CanvasState.prototype.addShape = function(shape) {
    this.shapes.push(shape);
    this.valid = false;
}

CanvasState.prototype.clear = function() {
    ctx.clearRect(0, 0, this.width, this.height);
}

// While draw is called as often as the INTERVAL variable demands,
// It only ever does something if the canvas gets invalidated by our code
CanvasState.prototype.draw = function() {
    // if our state is invalid, redraw and validate!
    if (!this.valid) {
        var ctx = this.ctx;
        var shapes = this.shapes;
        this.clear();

        // ** Add stuff you want drawn in the background all the time here **

        // draw all shapes
        var l = shapes.length;
        for (var i = 0; i < l; i++) {
            var shape = shapes[i];
            // We can skip the drawing of elements that have moved off the screen:
            if (shape.x > this.width || shape.y > this.height ||
                shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
            shapes[i].draw(ctx);
        }

        // draw selection
        // right now this is just a stroke along the edge of the selected Shape
        if (this.selection != null) {
            ctx.strokeStyle = this.selectionColor;
            ctx.lineWidth = this.selectionWidth;
            var mySel = this.selection;
            ctx.strokeRect(mySel.x, mySel.y, mySel.w, mySel.h);
        }

        // ** Add stuff you want drawn on top all the time here **

        this.valid = true;
    }
}


// Creates an object with x and y defined, set to the mouse position relative to the state's canvas
// If you wanna be super-correct this can be tricky, we have to worry about padding and borders
function getMouse(e) {
    var element = document.getElementById("theCanvas"), offsetX = 0, offsetY = 0, mx, my;

    // Compute the total offset
    if (element.offsetParent !== undefined) {
        do {
            offsetX += element.offsetLeft;
            offsetY += element.offsetTop;
        } while ((element = element.offsetParent));
    }

    // Add padding and border style widths to offset
    // Also add the <html> offsets in case there's a position:fixed bar
    offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
    offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;

    mx = e.pageX - offsetX;
    my = e.pageY - offsetY;

    // We return a simple javascript object (a hash) with x and y defined
    return {x: mx, y: my};
}


$(document).ready(function () {

    var canvas = document.getElementById("theCanvas");
    var ctx = canvas.getContext("2d");
    CanvasState(canvas);
    var startX = 0;
    var startY = 0;
    var mouseIsDown = false;
    $("#editor").hide();

    var param = {
        "user": "malte10",
        "template": true
    };

    $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        url: "http://whiteboard.apphb.com/Home/GetList",
        data: param,
        dataType: "jsonp",
        crossDomain: true,
        success: function (data) {
            $("#templateTemplate").tmpl(data).appendTo("#templateSelect");
        },
        error: function (xhr, err) {
            alert("error:\n" + xhr + "\n" + err);
        }
    });


    $("#undo").mousedown(function(e) {
        nextShape = shapes[shapes.length - 1];
        shapes.pop();
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        Redraw(ctx);
    });

    $("#redo").mousedown(function(e) {
        lastShape = shapes[shapes.length - 1];
        if (nextShape != undefined) {
            shapes.push(nextShape);
        }
        nextShape = undefined;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        Redraw(ctx);
    });

    $("#templateSelect").dblclick(function(e) {
        var item = this.options[this.selectedIndex].value;
        var param = { "id": item };

        $.ajax({
            type: "GET",
            contentType: "application/json; charset=utf-8",
            url: "http://whiteboard.apphb.com/Home/GetWhiteboard",
            data: param,
            dataType: "jsonp",
            crossDomain: true,
            success: function (data) {

                var items = JSON.parse(data.WhiteboardContents);
                for (var i = 0; i < items.length; i++) {
                    var func = eval(items[i].ClassName);
                    items[i].__proto__ = func.prototype;
                    shapes.push(items[i]);
                }

                Redraw(ctx);
            },
            error: function (xhr, err) {
                alert("error:\n" + xhr + "\n" + err);
            }
        });
    });

    $("#save").mousedown(function() {
        var name = prompt('Please enter a name for the template', '');
        if (name != null && name != "") {
            var param = { "user": "malte10",
                "name": name,
                "content": JSON.stringify(shapes),
                "template": true
            };
            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "http://whiteboard.apphb.com/Home/Save",
                data: param,
                dataType: "jsonp",
                crossDomain: true,
                success: function (data) {
                    var arr = [
                        { "ID": data.ID,
                            "WhiteboardTitle": title
                        }
                    ];
                    $("#templateTemplate").tmpl(arr).appendTo("#templateSelect"); // �arf a� nota til a� breyta einhverju template lista � �ennan lista.
                },
                error: function (xhr, err) {
                    alert("error");
                }

            });

        }

    });


    $("#theCanvas").mousedown(function(e) {   //offset, page,screen,client
        mouseIsDown = true;
        var x = e.offsetX;
        var y = e.offsetY;
        startX = x;
        startY = y;
        var checkX;
        var checkY;
        var checkEndX;
        var checkEndY;
        if (isMoveable == true) {     //TODO virkar ekki almennilega
            var mx = startX;
            var my = startY;
            var l = shapes.length;
            for (var i = l - 1; i >= 0; i--) {
                checkX = shapes[i].x;
                checkY = shapes[i].y;
                checkEndX = shapes[i].endX;
                checkEndY = shapes[i].endY;
                if (e.pageX < checkEndX + (e.pageX - e.offsetX) && e.pageX > checkX +
                    (e.pageX - e.offsetX) && e.pageY < checkEndY + (e.pageY - e.offsetY) &&
                    e.pageY > checkY + (e.pageY - e.offsetY)) {
                    var mySel = shapes[i];
                    // Keep track of where in the object we clicked
                    // so we can move it smoothly (see mousemove)
                    this.dragoffx = mx;
                    this.dragoffy = my;
                    this.dragging = true;
                    this.selection = mySel;
                    this.valid = true;
                    return;
                }
            }
            // havent returned means we have failed to select anything.
            // If there was an object selected, we deselect it
            if (this.selection) {
                this.selection = null;
                this.valid = false; // Need to clear the old selection border
            }
        } else if (isText == true) {
            $("#text").css("left", e.offsetX);
            $("#text").css("top", e.offsetY + 100);
            $("#text").show();
            textX = x;
            testY = y;
        } else if (isEq == true) {
            $("#preview").show();
            $("#editor").show();
            $("#preview").css("left", 600);
            $("#eqEditor").css("left", e.offsetX);
            $("#eqEditor").css("top", e.offsetY + 100);
            $("#eqEditor").show();
            textX = x;
            testY = y;
        }
        else {
            $("#eqEditor").val('');
            $("#eqEditor").hide();
            $("#text").val('Insert Text');
            $("#text").hide();  // �etta virkar f�nt
            shapes.push(factory(startX, startY, theBorder, theFill, theLineSize));
        }


    });

    $("#theCanvas").mousemove(function(e) {
        if (isText == true) {
        }
        else if (mouseIsDown == true) {

            var x = e.offsetX;
            var y = e.offsetY;
            var lastShape = shapes[shapes.length - 1];
            if (lastShape != undefined) {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                if (this.dragging == false) {
                    lastShape.SetEnd(x, y);
                }
                Redraw(ctx);
            }
            if (this.dragging) {
                var mouse = getMouse(e);	// TODO virkar ekki.
                var startX = this.selection.x;
                var startY = this.selection.y
                var slideX = mouse.x - startX;
                var slideY = mouse.y - startY;
                this.selection.endX = this.selection.endX + (slideX);
                this.selection.endY = this.selection.endY + (slideY);
                this.selection.x = this.selection.x + (slideX);
                this.selection.y = this.selection.y + (slideY);
                this.valid = false; // Something's dragging so we must redraw
            }


        }
    });

    $("#theCanvas").mouseup(function(e) {
        mouseIsDown = false;
        this.dragging = false;
        this.valid = true;//nota� svo hann h�tti a� dragga sama hlutinn endalaust.
        lastShape = shapes[shapes.length - 1];
        isMoveable = false;
    });

    $("#text").keydown(function(e) {
        var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
        if (theCode == 13) {
            var x = e.srcElement.offsetLeft;
            var y = e.srcElement.offsetTop;
            var text = document.getElementById("text").value;
            var newFont = document.getElementById("newFont");
            newFont = newFont.options[newFont.selectedIndex].value;
            var newSize = document.getElementById("newSize");
            newSize = newSize.options[newSize.selectedIndex].value;
            shapes.push(createText(x, y, text, theBorder, theFill, newFont, newSize));
            Redraw(ctx);
            isText = false;
            $("#text").hide();
            return false;
        }
    });

    $("#eqEditor").keydown(function(e) {
        var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
        if (theCode == 13) {
            var x = e.srcElement.offsetLeft;
            var y = e.srcElement.offsetTop;
            var eq = document.getElementById("equation").attributes[1].value;
            shapes.push(createImg(x, y, eq));
            Redraw(ctx);
            isEq = false;
            $("#eqEditor").val('');
            $("#eqEditor").hide();
            $("#editor").hide();
            $("#preview").hide();
            return false;
        }

    });
});